#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2025 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import logging
import re
import json
from utils import utils_data, ErrorInfoBuilder

logger = logging.getLogger('my_logger')


class Level:
    testcase_regex = {
        'arkts': re.compile(r'^\s*it\s*\(\s*["\'](.*?)["\']\s*,'),
        'javascript': re.compile(r'^\s*it\s*\(\s*["\'](.*?)["\']\s*,'),
        'c++': re.compile(r'^\s*HWTEST_F\(|\s*HWTEST\(')
    }

    language_map = {
        '.test.ets': 'arkts',
        '.test.js': 'javascript',
        '.cpp': 'c++'
    }

    @classmethod
    def _find_testcases(cls, file_entities, language):
        for file_entity in file_entities:
            file_path = file_entity.full_path
            testcase_regex_to_use = cls.testcase_regex[language]
            try:
                with open(file_path, 'r', encoding='utf-8') as file:
                    lines = file.readlines()
                    testcases = []
                    start_line = 0
                    i = 0
                    while i < len(lines):
                        testcase_match = testcase_regex_to_use.search(lines[i])
                        if testcase_match:
                            start = i
                            open_count = 1
                            end = i
                            for j in range(i + 1, len(lines)):
                                open_count += lines[j].count('(')
                                open_count -= lines[j].count(')')
                                if open_count == 0:
                                    end = j
                                    break
                            testcases.append((start, end))
                            i = end + 1
                        else:
                            i += 1
                    if not testcases:
                        continue
                    yield file_path, lines, testcases
            except Exception as e:
                logger.error(f"Error reading file {file_path}: {e}")

    @classmethod
    def check_tc_number(cls):
        has_error = False
        file_entities = utils_data.get_file()

        def get_language(file_name):
            for suffix, lang in cls.language_map.items():
                if file_name.endswith(suffix):
                    return lang
            return None

        for file_entity in file_entities:
            file_name = file_entity.file_name
            language = get_language(file_name)
            if language is None:
                continue
            for file_path, lines, testcases in cls._find_testcases([file_entity], language):
                if cls.check_duplicate_tc_numbers_in_file(lines, file_entity.file_path, language):
                    has_error = True
                if cls.check_duplicate_tc_numbers_with_siblings(lines, file_entity, language):
                    has_error = True
                for start, end in testcases:
                    if cls.check_tc_number_in_range(lines, start, end, cls.tc_number_regex, language,
                                                    file_entity.file_path):
                        has_error = True
        if has_error:
            logger.info("测试用例@tc.number注释检查完成，错误信息已写入xts_result.json")
        else:
            logger.info("测试用例@tc.number注释检查通过")

    @classmethod
    def check_level(cls):
        has_error = False
        file_entities = utils_data.get_file()

        def get_language(file_name):
            for suffix, lang in cls.language_map.items():
                if file_name.endswith(suffix):
                    return lang
            return None

        for file_entity in file_entities:
            file_name = file_entity.file_name
            language = get_language(file_name)
            if language is None:
                continue

            for file_path, lines, testcases in cls._find_testcases([file_entity], language):
                for start, end in testcases:
                    first_line_number = start + 1
                    first_line_code = lines[start].strip()

                    try:
                        full_case = ''.join(lines[start:end + 1])
                    except IndexError:
                        full_case = ''

                    if language in ['arkts', 'javascript']:
                        try:
                            args = cls._parse_args(full_case)
                        except Exception as e:
                            logger.error(f"解析ets/js用例参数失败: {e}")
                            args = []

                        if len(args) < 2:
                            error_info = ErrorInfoBuilder() \
                                .set_buggy_file_path(file_entity.file_path) \
                                .set_defect_type("XTS.CHECK.LEVEL.01") \
                                .set_description("ets和js文件的用例至少需要两个参数") \
                                .set_main_buggy_line(first_line_number) \
                                .set_main_buggy_code(first_line_code) \
                                .set_language(language) \
                                .build()
                            utils_data.write_error_to_json_file(error_info)
                            logger.info(json.dumps(error_info, indent=4, ensure_ascii=False))
                            has_error = True
                            continue

                        second_arg = args[1]
                        valid_levels = [f'Level.LEVEL{i}' for i in range(0, 5)]
                        if not any(level in second_arg for level in valid_levels):
                            error_info = ErrorInfoBuilder() \
                                .set_buggy_file_path(file_entity.file_path) \
                                .set_defect_type("XTS.CHECK.LEVEL.01") \
                                .set_description("ets和js文件用例的第二个参数必须要有Level用例级别") \
                                .set_main_buggy_line(first_line_number) \
                                .set_main_buggy_code(first_line_code) \
                                .set_language(language) \
                                .build()
                            utils_data.write_error_to_json_file(error_info)
                            logger.info(json.dumps(error_info, indent=4, ensure_ascii=False))
                            has_error = True

                    elif language == 'c++':
                        try:
                            args = cls._parse_args(full_case)
                        except Exception as e:
                            logger.error(f"解析cpp用例参数失败: {e}")
                            args = []

                        if len(args) < 3:
                            error_info = ErrorInfoBuilder() \
                                .set_buggy_file_path(file_entity.file_path) \
                                .set_defect_type("XTS.CHECK.LEVEL.01") \
                                .set_description("cpp文件的用例至少需要三个参数") \
                                .set_main_buggy_line(first_line_number) \
                                .set_main_buggy_code(first_line_code) \
                                .set_language(language) \
                                .build()
                            utils_data.write_error_to_json_file(error_info)
                            logger.info(json.dumps(error_info, indent=4, ensure_ascii=False))
                            has_error = True
                            continue

                        third_arg = args[2]
                        valid_levels = [f'Level{i}' for i in range(0, 5)]
                        if not any(level in third_arg for level in valid_levels):
                            error_info = ErrorInfoBuilder() \
                                .set_buggy_file_path(file_entity.file_path) \
                                .set_defect_type("XTS.CHECK.LEVEL.01") \
                                .set_description("cpp文件用例的第三个参数必须要有Level用例级别") \
                                .set_main_buggy_line(first_line_number) \
                                .set_main_buggy_code(first_line_code) \
                                .set_language(language) \
                                .build()
                            utils_data.write_error_to_json_file(error_info)
                            logger.info(json.dumps(error_info, indent=4, ensure_ascii=False))
                            has_error = True

        if has_error:
            logger.info("测试用例级别入参检查完成，错误信息已写入xts_result.json")
        else:
            logger.info("测试用例级别入参检查通过")

    @classmethod
    def _parse_args(cls, full_case):
        try:
            args_str = full_case.split('(', 1)[1].rsplit(')', 1)[0]
        except IndexError:
            return []

        args = []
        current_arg = ""
        open_count = 0
        for char in args_str:
            if char == '(':
                open_count += 1
            elif char == ')':
                open_count -= 1
            elif char == ',' and open_count == 0:
                args.append(current_arg.strip())
                current_arg = ""
                continue
            current_arg += char
        args.append(current_arg.strip())
        return args